﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConfeccionesJR.Entites;
using ConfeccionesJR.Repository;
using Microsoft.Practices.Unity;

namespace ConfeccionesJR.BussinesLogic
{
    public class ProductoBL : IProductoBL
    {
        [Dependency]
        public IProductoRepository productoRepository { get; set; }

        [Dependency]
        public IDetalleProductoRepository detProductoRepository { get; set; }

        [Dependency]
        public IMaterialRepository materialRepository { get; set; }

        [Dependency]
        public IUnidadMedidaRepository undMedidaRepository { get; set; }

        public List<PRODUCTO> GetAllFromProducto()
        {
            return productoRepository.GetAllFromProducto();
        }

        public List<PRODUCTO> GetFromProductoByDescripcion(string descripcion)
        {
            return productoRepository.GetFromProductoByDescripcion(descripcion);
        }

        public List<PRODUCTO> GetAllFromProductosByDescripcionAndStockBajo(string descripcion, int minStock)
        {
            return productoRepository.GetAllFromProductosByDescripcionAndStockBajo(descripcion, minStock);
        }

        public PRODUCTO GetOneProductoByDescripcion(string codigo)
        {
            return productoRepository.GetOneProductoByDescripcion(codigo);
        }

        public PRODUCTO GetFromProductoById(int id)
        {
            return productoRepository.GetFromProductoById(id);            
        }

        public void AddProducto(PRODUCTO producto)
        {
            var duplicidad = productoRepository.ExisteDuplicidadProdDescripcion(producto.Descripcion, producto.Id);

            if (!duplicidad)
            {
                var msg = "";
                var ok = producto.Validate(out msg);

                if (ok)
                {
                    if (producto.Precio > producto.Costo)
                    {
                        ValidarStockMterial(producto);

                        productoRepository.AddProducto(producto);

                        #region UpdateStockMaterial
                        foreach (var item in producto.DETALLE_PRODUCTO)
                        {
                            var material = materialRepository.GetFromMaterialById(item.materialId);
                            material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                            material.Stock = material.Stock - item.Cantidad * producto.Stock;
                            materialRepository.UpdateMaterial(material);
                        }
                        #endregion
                    }
                    else
                    {
                        var error = string.Format("El precio debe ser mayor al costo");
                        throw new Exception(error);
                    }    
                }
                else
                {
                    throw new Exception(msg);
                }
            }
            else
            {
                var error = string.Format("Ya existe un producto con la misma descripción\n" +
                    "Producto: " + producto.Descripcion);
                throw new Exception(error);
            }          
        }

        public void UpdateProdConMaterial(PRODUCTO producto)
        {
            var duplicidad = productoRepository.ExisteDuplicidadProdDescripcion(producto.Descripcion, producto.Id);

            if (!duplicidad)
            {
                var msg = "";
                var ok = producto.Validate(out msg);
                if (ok)
                {
                    if (producto.Precio > producto.Costo)
                    {
                        ValidarStockMterial(producto);

                        UpdateStockMateriales(producto);

                        productoRepository.UpdateProdConMaterial(producto);
                    }
                    else
                    {
                        var error = string.Format("El precio debe ser mayor al costo");
                        throw new Exception(error);
                    }
                }
                else
                {
                    throw new Exception(msg);
                }
            }
            else
            {
                var error = string.Format("Ya existe un producto con la misma descripción: \n{0}", producto.Descripcion);
                throw new Exception(error);
            }
        }

        public void UpdateSoloProducto(PRODUCTO producto)
        {
            var msg = "";
            var ok = producto.Validate(out msg);
            if (ok)
            {
                productoRepository.UpdateSoloProducto(producto);
            }
            else
            {
                throw new Exception(msg);
            }
        }

        private void UpdateStockMateriales(PRODUCTO producto)
        {
            foreach (var item in producto.DETALLE_PRODUCTO)
            {
                var existeDetMat = detProductoRepository.GetFromMaterialByDetalleProductoId(item.materialId, item.productoId);

                #region NoCambiaStock
                if (existeDetMat.PRODUCTO.Stock == producto.Stock)  // no importa el stock
                {
                    if (existeDetMat != null) //material existente
                    {
                        if (item.Cantidad != existeDetMat.Cantidad)
                        {
                            var material = materialRepository.GetFromMaterialById(item.materialId);
                            material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                            material.Stock = (material.Stock + existeDetMat.Cantidad * existeDetMat.PRODUCTO.Stock) - item.Cantidad * producto.Stock;
                            materialRepository.UpdateMaterial(material);
                        }
                    }
                    else //material no existente
                    {
                        var material = materialRepository.GetFromMaterialById(item.materialId);
                        material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                        material.Stock = material.Stock - item.Cantidad * producto.Stock;
                        materialRepository.UpdateMaterial(material);
                    }
                }
                #endregion
                ////////////////////////////////////
                #region cambioStock
                else
                {
                    if (existeDetMat != null)//material existente
                    {
                        var material = materialRepository.GetFromMaterialById(item.materialId);
                        material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                        material.Stock = (material.Stock + existeDetMat.Cantidad * existeDetMat.PRODUCTO.Stock) - item.Cantidad * producto.Stock;
                        materialRepository.UpdateMaterial(material);

                        //if (item.Cantidad != existeDetMat.Cantidad)
                        //{
                        //    var material = materialRepository.GetFromMaterialById(item.materialId);
                        //    material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                        //    material.Stock = (material.Stock + existeDetMat.Cantidad * existeDetMat.PRODUCTO.Stock) - item.Cantidad * producto.Stock;
                        //    materialRepository.UpdateMaterial(material);
                        //}
                        //else //material no existente
                        //{
                        //    var material = materialRepository.GetFromMaterialById(item.materialId);
                        //    material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                        //    material.Stock = (material.Stock + existeDetMat.Cantidad * existeDetMat.PRODUCTO.Stock) - item.Cantidad * producto.Stock;
                        //    materialRepository.UpdateMaterial(material);
                        //}
                    }
                #endregion
                    else
                    {
                        var material = materialRepository.GetFromMaterialById(item.materialId);
                        material.UNIDAD_MEDIDA = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);
                        material.Stock = material.Stock - item.Cantidad * producto.Stock;
                        materialRepository.UpdateMaterial(material);
                    }
                }
            }
            
        }

        private void ValidarStockMterial(PRODUCTO producto)
        {
            foreach (var item in producto.DETALLE_PRODUCTO)
            {
                var material = materialRepository.GetFromMaterialById(item.materialId);
                var undMatr = undMedidaRepository.GetFromUnidadMedidaById(material.unidadMedidaId);

                var existeDetMat = detProductoRepository.GetFromMaterialByDetalleProductoId(item.materialId, item.productoId);
                
                if (existeDetMat == null)
                {
                    if (item.Cantidad * producto.Stock > material.Stock)
                    {
                        throw new Exception(string.Format("No hay Stock suficiente para el material {0}," +
                                          " solo quedan {1} {2}", material.Descripcion, Math.Round(material.Stock,2), undMatr.Descripcion));
                    }
                }
                if (existeDetMat != null)
                {
                    var stockActual = material.Stock + existeDetMat.Cantidad * existeDetMat.PRODUCTO.Stock;
                    
                    if (item.Cantidad * producto.Stock > stockActual)
                    {
                        throw new Exception(string.Format("La maxima cantidad a elegir del material {0}," +
                                          " es {1} {2}", material.Descripcion, Math.Round(stockActual,2), undMatr.Descripcion));
                    }
                }
            }
        }

        public bool ExisteDuplicidadProdDescripcion(string prodDescripcion, int id)
        {
            return productoRepository.ExisteDuplicidadProdDescripcion(prodDescripcion, id);
        }

    }
}
